/**
 * Kernel Monkeys
 * Andrew Boguk
 * Sergiy Kulyk
 * Nicholas Swartzendruber
 */

/*
 *  process.c
 *
 *  Created on: May 15, 2011
 *  Author: Sergiy Kulyk
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "process.h"


/*******************************************************************
 * 		Request													   *
 ******************************************************************/

/**
 * Request type constructor.
 */
request_t * request_new(const int step,
                        const enum request_type_t type) {

    request_t * request =
        (request_t *) malloc(sizeof(request_t));
    if (request) {
        request->step = step;
        request->type = type;
    }
    return request;
}



/*******************************************************************
 * 		Process													   *
 ******************************************************************/

/**
 * Process constructor. Returns a pointer to a new process record, or
 * a null pointer if it was unable to obtain memory for it.
 */
process_t * process_new(const int id,
		                const int steps,
                        const int num_req,
                        request_t** req_type,
                        enum process_type_t p_type) {

    process_t * p = NULL;

    // working with a flexible array member is tricky
    // http://stackoverflow.com/questions/246977/flexible-array-members-in-c-bad
    p = (process_t *) malloc(sizeof(process_t));

    if (p) {
    	p->id = id;
        p->num_steps = steps;
        p->num_requests = num_req;
        p->process_type = p_type;

        p->req_type = req_type;

        /*
        int i;
        for (i = 0; i < num_req; i++) {
        	p->req_type[i] = req_type[i];
        }
        */


    }
    return p;
}



/**
 * Process destructor. Frees the memory and sets the pointer to NULL.
 *
 * @param process Pointer to the process to be deleted. After the process is
 *                deleted, this pointer will be set to Null. *
 * @return Error code:
 * 			0: everything went well;
 * 			1: pointer is null;
 * 			2: other error.
 */
int process_delete(process_t* process) {

	if (process == NULL) {
		return 1;
	}

	free(process);
	process = NULL;

	return 0;
}


/**
 * Run the process. This function will "run" the process until it gets to the
 * first I/O request. Then it stops and returns the next step value, also
 * the provided request to an appropriate type.
 *
 * @param process Process pointer.
 * @param next_step Next step to run.
 * @param request Request type.
 * @return Step to start from at the next run.
 */
int process_run(const process_t * process,
		        int next_step,
		        enum request_type_t * request) {

	// figure out when next to request I/O
	int io_index;
	for (io_index = 0; io_index < process->num_requests; io_index++) {
		if (process->req_type[io_index]->step >= next_step) {
			break;
		}
	}
	if (io_index == process->num_requests) {
		io_index = 0;
	}

	//TODO debug
	printf("[process.c] io_index = %d, next io request is at %d\n", io_index, process->req_type[io_index]->step);

	// number of "work" steps to do before the next I/O request
	int num_steps =
			abs(process->num_steps - process->num_steps - abs(next_step - process->req_type[io_index]->step));
	int i;
	for (i = 0; i < num_steps; i++) {
		usleep(WORK_UNIT);
	}

	//TODO debug
	printf("[process.c] slept through %d steps\n", num_steps);

	*request = process->req_type[io_index]->type;

	//TODO debug
	printf("[process.c] request type returned: %d\n", *request);

	return process->req_type[io_index]->step + 1;
}
